package XMFramework.Core
{
	import XMFramework.Core.Internal.SResourceLoader;
	import XMFramework.Interface.ISoundFX;
	
	import flash.events.Event;
	import flash.media.Sound;
	import flash.media.SoundChannel;
	import flash.utils.Dictionary;

	public class SSoundFX implements ISoundFX
	{
		/**
		 * List of SWF bucket information 
		 */		
		private var bucketData : Dictionary				=	new Dictionary( true );
		
		/**
		 * List of sfx object information
		 */		
		private var sfxData : Dictionary				=	new Dictionary( true );
		
		/**
		 * List of currently playing sound
		 * Used when user force to stop all sound currently playing 
		 */		
		private var curPlayingSound : Dictionary		=	new Dictionary();
		
		/**
		 * List of sfx object is waiting for resource downloading progress. 
		 * These sfx will play after resource download complete 
		 */		
		private var latencyPlayingSound : Array			=	new Array();
			
		private var muteSounds : Boolean				=	false;
		
		/**
		 * Constructor 
		 * @param mediaPath
		 * @param data
		 * 
		 */		
		public function loadConfigData( mediaPath : String, data : Object ) : void
		{
			var index : String;			
			
			// Parse resource bucket information
			var buckets : Object	=	data.buckets;			
			for( index in buckets )
			{				
				// Create new swf resource loader
				var resName : String			=	buckets[index].name;
				var resURL : String				=	mediaPath + buckets[index].url;
				
				var loader : SResourceLoader	=	new SResourceLoader( resName, resURL, "demand" );
				
				var bucket : Object				=	new Object();
				bucket["name"]					=	buckets[index].name;
				bucket["loader"]				=	loader;
				
				bucketData[bucket.name]			=	bucket;
			}
			
			// Parse sfx symbol information
			var sfx : Object	=	data.sfx;			
			for( index in sfx )
			{			
				var tag : Object				=	new Object();
				
				tag["bucket"]					=	sfx[index].bucket;
				tag["id"]						=	sfx[index].id;				
				tag["symbol"]					=	sfx[index].symbol;	
				
				sfxData[tag.id]					=	tag;
			}
		}
		
		/////////////////////////////////////////////////////
		// Implements
		
		public function playSound( id : String, loops : int = 1, firstLoadedPlay : Boolean = false, onPlayComplete : Function = null ) : void
		{
			if( sfxData.hasOwnProperty( id ) )
			{
				var tag : Object				=	sfxData[id];
				
				if( bucketData.hasOwnProperty( tag.bucket ) )
				{
					var loader : SResourceLoader	=	bucketData[tag.bucket].loader;
					
					// Play immediately if resource exist
					if( loader.isLoaded )
					{
						loader.getClassFunc( tag.symbol, playLoadedResource, null );					
					}
					else
					{
						if( firstLoadedPlay )
						{
							var waiting : Object		=	new Object();
							waiting["bucket"]			=	bucketData[tag.bucket].name;
							waiting["symbol"]			=	tag.symbol;
							waiting["id"]				=	id;
							waiting["loops"]			=	loops;
							waiting["onPlayComplete"]	=	onPlayComplete;
							
							latencyPlayingSound.push( waiting );
							
							loader.getClassFunc( tag.symbol, playLatencyResource, null );							
						}
						
						// Just prepair resource for next time use
						else
						{
							loader.loadResource();
						}
					}
				}
			}
			
			function playLoadedResource( bucket : String, className : String, res : Class ) : void
			{				
				var instRes : *	=	new res;				
				var soundObj : Sound	=	instRes as Sound;
				if( soundObj && ! muteSounds )
					startPlaySound( id, soundObj, loops, onPlayComplete );
			
				// Release unusable resource
				else
					instRes	=	null;
			}	
		}
		
		public function isPlayingSound( id : String ) : Boolean
		{
			for( var obj : Object in curPlayingSound )
				if( curPlayingSound[obj] == id )
					return true;
			
			return false;
		}
		
		public function stopSound( id : String ) : void
		{
			for( var obj : Object in curPlayingSound )
			{
				if( curPlayingSound[obj] == id )
				{					
					var channel : SoundChannel	=	obj.channel as SoundChannel;
					channel.stop();
					channel.removeEventListener( Event.SOUND_COMPLETE, soundPlayCompleteHandler );
					delete curPlayingSound[obj];
					
					break;
				}
			}
		}
		
		public function stopAllSound() : void
		{
			for( var obj : Object in curPlayingSound )
			{
				var channel : SoundChannel	=	obj.channel as SoundChannel;
				channel.stop();
				channel.removeEventListener( Event.SOUND_COMPLETE, soundPlayCompleteHandler );
			}
			
			curPlayingSound	=	new Dictionary();
		}
		
		public function set mute( val : Boolean ) : void
		{
			muteSounds	=	val;
			if( val )
				stopAllSound();
		}
		
		public function get mute() : Boolean
		{
			return muteSounds;
		}
		
		////////////////////////////////////////////////////
		private function startPlaySound( id : String, soundObj : Sound, loops : int, onPlayComplete : Function ) : void
		{			
			var channel : SoundChannel;
			var obj : Object;
			
			try
			{
				channel	=	soundObj.play( 0, loops );
				channel.addEventListener( Event.SOUND_COMPLETE, soundPlayCompleteHandler );
				
				obj		=	new Object();
				obj["channel"]				=	channel;
				obj["onPlayComplete"]		=	onPlayComplete;
				obj["id"]					=	id;
				
				// Add to current playing list
				curPlayingSound[obj]		=	id;
			}
			catch( ex : * ){}
		}
		
		private function soundPlayCompleteHandler( event : Event ) : void
		{
			var soundObj : SoundChannel	=	event.currentTarget as SoundChannel;
			for( var obj : Object in curPlayingSound )
			{
				if( obj.channel == soundObj )
				{
					if( obj.onPlayComplete != null )
						obj.onPlayComplete.apply( null, [obj.id] );
					
					soundObj.removeEventListener( Event.SOUND_COMPLETE, soundPlayCompleteHandler );
					delete curPlayingSound[obj];
					
					break;
				}
			}
		}
		
		private function playLatencyResource( bucket : String, className : String, res : Class ) : void
		{
			for( var index : String in latencyPlayingSound )
			{
				var waiting : Object	=	latencyPlayingSound[index];
				if( waiting.bucket == bucket && waiting.symbol == className )
				{
					var instRes : *			=	new res;
					var soundObj : Sound	=	instRes as Sound;
					if( soundObj && ! muteSounds )
						startPlaySound( waiting.id, soundObj, waiting.loops, waiting.onPlayComplete );
					
					// Remove from waiting for playing list
					latencyPlayingSound.splice( index, 1 );
					break;
				}
			}
		}
	}
}